package main

import (
	"github.com/pkg/errors"
	"log"
	"reflect"
)

type Channels struct {
	ChannelId int64 `sql:"channel_id" json:"channel_id"`
	Optional int `sql:"optional" json:"optional"`
	Type int `sql:"type" json:"type"`
	Ratio int `sql:"ratio" json:"ratio"`
	Name string `sql:"name" json:"name"`
	Visible int `sql:"visible" json:"visible"`
}

type WhereOp struct {
	op string
	opr string
	filed string
}

type Field map[string]string

type DbSelecter struct {
	filed Field
	db  string
	where []WhereOp
}

func SelectOp(filed string,op string,opr string) WhereOp  {
	return WhereOp{op,opr,filed}
}

func DbSelecterFactory(field Field,db string,where []WhereOp)  DbSelecter{
	return DbSelecter{field,db,where}
}

func (this DbSelecter) AppendWhere(op WhereOp)  {
	this.where = append(this.where,op)
}

func (this DbSelecter)GenSql() string {
	ret := "select "
	for k,v := range this.filed{
		if ret == "select "{
			if k != v{
				ret += k + " as " + v
			}else{
				ret += k + " "
			}
		}else{
			if k != v{
				ret += ", " + k + " as " + v
			}else{
				ret += ", " + k
			}
		}
	}
	ret += " from " + this.db + " where "
	iffirst := false
	for _,v := range this.where{
		if !iffirst{
			iffirst = true
			switch v.op {
			case "like":
				ret +=  v.filed + " like '"  + v.opr + "'"
				break
			case "eq":
				ret +=  v.filed +  " = '" + v.opr + "'"
			case "lt":
				ret +=  v.filed + " < '" + v.opr + "'"
			case "gt":
				ret +=  v.filed + " > '" + v.opr + "'"
			case "lte":
				ret +=  v.filed + " <= '"  + v.opr + "'"
			case "gte":
				ret +=  v.filed + " >= '"  + v.opr + "'"
			case "between":
				ret += " and " + v.filed + " between " + v.opr
			}
		}else{
			switch v.op {
			case "like":
				ret += " and " +  v.filed + " like '"  + v.opr + "'"
				break
			case "eq":
				ret += " and " + v.filed +  " = '" + v.opr + "'"
			case "lt":
				ret += " and " + v.filed + " < '" + v.opr + "'"
			case "gt":
				ret += " and " + v.filed + " > '" + v.opr + "'"
			case "lte":
				ret += " and " + v.filed + " <= '"  + v.opr + "'"
			case "gte":
				ret += " and " + v.filed + " >= '"  + v.opr + "'"
			case "between":
				ret += " and  " + v.filed + " between " + v.opr
			}
		}
	}
	return  ret
}

func DBStructField(db interface{}) (error,Field){
	ret := Field{}
	kind := reflect.TypeOf(db).Kind()
	if kind != reflect.Struct{
		return errors.New("not a db instance"),nil
	}
	tp := reflect.TypeOf(db)
	for i := 0;i < tp.NumField();i++{
		if tp.Field(i).Tag.Get("sql") != ""{
			ret[ string(tp.Field(i).Tag.Get("sql"))] = string(tp.Field(i).Tag.Get("sql"))
		}
	}
	return  nil,ret
}

func DBSliceField (b []string) Field {
	ret := Field{}
	for _,v := range b{
		ret[v] = v
	}
	return ret
}

func (this Field)SetNickFileds(f string,nick string)  {
	if _,ok := this[f];ok{
		this[f] = nick
	}
}

func main()  {
	e,fs  :=  DBStructField(Channels{})
	if nil != e{
		log.Print(e.Error())
	}
	fs.SetNickFileds("optional","ipo1")
	log.Print(fs)
	dbSelector := DbSelecterFactory(fs,"channels",[]WhereOp{SelectOp("ipo1","lt","1"),SelectOp("id","gt","1")})
	log.Print(dbSelector.GenSql())
}